parser grammar AnalexXMLParser;

options {
  language = Java;
  tokenVocab = AnalexXMLLexer;
}

@header {
  package Practica9.Errores;
}

@members {
  private ArrayList<String> errors = new ArrayList<String>();
  
  protected Object recoverFromMismatchedToken(IntStream input, int ttype,BitSet follow) throws RecognitionException {   
      throw new MismatchedTokenException(ttype, input);
  }
  
  public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
    String hdr = getErrorHeader(e);
    String msg = getErrorMessage(e, tokenNames);
    errors.add(hdr + " " + msg);
  }
   
  public ArrayList<String> getErrors() {
    return errors;
  }
  
  public String ErrorReportTag(Token st, Token tag, Token end, Token input){
    String msg = input.getText();
    boolean error = false;
    try {
      if (!st.getText().equals(input.getText()))
        msg = st.getText() + msg;
    } catch (NullPointerException npe) { error = true; }
    try {
      if (!tag.getText().equals(input.getText()))
        msg = st.getText() + tag.getText() + msg;
    } catch (NullPointerException npe) { error = true; }
    try {
      if (!end.getText().equals(input.getText()))
        msg = st.getText() + tag.getText() + end.getText();
    } catch (NullPointerException npe) { error = true; }
    
    if (!error)
      return null;
    return msg; 
  }
}

entrada: tag;

tag: st_biblio (tagLibro|PCDATA)* end_biblio;

tagLibro: st_libro PCDATA? (tagTitulo)? tagAutor (tagEditorial)? end_libro;
tagTitulo: st_titulo PCDATA? end_titulo;
tagEditorial: st_editorial PCDATA? end_editorial;

tagAutor
  : ini=st_autor texto=PCDATA end_autor;
  catch [RecognitionException except]
  {
    Token t = input.LT(1);
    try {
      if (texto.getText().equals(t.getText())) {}
    } catch (NullPointerException npe) {
      emitErrorMessage("Es necesario especificar un autor en este caso no existe ninguno");
    }
    
    String txt = $ini.err;
    RecognitionException reg = $ini.reg;
    if (reg != null) {
      emitErrorMessage("Se esperaba <autor> y se encontró " + txt);
    }
    else
      throw except;
  } 
  
atributos: ID ATTR_EQ ATTR_VALUE ; 

st_biblio: INIT_TAG KEYWORD_BIBLIOTECA   (atributos)* FIN_TAG;
st_libro:  INIT_TAG KEYWORD_LIBRO        (atributos)* FIN_TAG;

st_autor returns [RecognitionException reg = null, String err = ""]
  : initag=INIT_TAG autor=KEYWORD_AUTOR         (atributos)* fintag=FIN_TAG;
  catch [RecognitionException re]{
    Token t = input.LT(1);
    $err = ErrorReportTag(initag,autor,fintag,t);
    
    if ($err != null) 
      $reg = re;
  }


st_titulo: INIT_TAG KEYWORD_TITULO       (atributos)* FIN_TAG;
st_editorial: INIT_TAG KEYWORD_EDITORIAL (atributos)* FIN_TAG;

end_biblio
  : ini=OUT_TAG txttag=KEYWORD_BIBLIOTECA fin=FIN_TAG;
  catch [RecognitionException except]
  {
    Token t = input.LT(1);
    String msg = ErrorReportTag(ini, txttag, fin, t);
    emitErrorMessage("Falta cerrar la etiqueta <biblioteca>. Se esperaba </biblioteca>" +
    " encontrado " + msg);
  } 
  
end_libro
  : ini=OUT_TAG txttag=KEYWORD_LIBRO fin=FIN_TAG;
  catch [RecognitionException except]
  {
    Token t = input.LT(1);
    String msg = ErrorReportTag(ini, txttag, fin, t);
    emitErrorMessage("Falta cerrar la etiqueta <libro>. Se esperaba </libro>" +
    " encontrado " + msg);  
  }

end_titulo
  : ini=OUT_TAG txttag=KEYWORD_TITULO fin=FIN_TAG;
  catch [RecognitionException except]
  {
    Token t = input.LT(1);
    String msg = ErrorReportTag(ini, txttag, fin, t);
    emitErrorMessage("Falta cerrar la etiqueta <titulo>. Se esperaba </titulo>" +
    " encontrado " + msg);
  } 

end_autor
  : ini=OUT_TAG txttag=KEYWORD_AUTOR fin=FIN_TAG;
  catch [RecognitionException except]
  {
    Token t = input.LT(1);
    String msg = ErrorReportTag(ini, txttag, fin, t);
    emitErrorMessage("Falta cerrar la etiqueta <autor>. Se esperaba </autor>" +
    " encontrado " + msg);
  } 

end_editorial
  : ini=OUT_TAG txttag=KEYWORD_EDITORIAL fin=FIN_TAG;
  catch [RecognitionException except]
  {
    Token t = input.LT(1);
    String msg = ErrorReportTag(ini, txttag, fin, t);
    emitErrorMessage("Falta cerrar la etiqueta <editorial>. Se esperaba </editorial>" +
    " encontrado " + msg);
  } 